package org.loong.crypto.extension.operator;

import java.util.HashMap;
import java.util.Map;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;

public class DefaultAlgorithmNameFinder implements AlgorithmNameFinder {

    public static final Map<ASN1ObjectIdentifier, String> ALGORITHMS = new HashMap<>();

    public static final Map<ASN1ObjectIdentifier, String> DIGESTS = new HashMap<>();

    static {
        ALGORITHMS.put(NISTObjectIdentifiers.aes, "AES");
        ALGORITHMS.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
        ALGORITHMS.put(GMObjectIdentifiers.sm2p256v1, "SM2");
        ALGORITHMS.put(GMObjectIdentifiers.sm_scheme.branch("104"), "SM4");
        
        ALGORITHMS.put(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1WithDSA");
        ALGORITHMS.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WithDSA");
        ALGORITHMS.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WithDSA");
        ALGORITHMS.put(NISTObjectIdentifiers.dsa_with_sha384, "SHA384WithDSA");
        ALGORITHMS.put(NISTObjectIdentifiers.dsa_with_sha512, "SHA512WithDSA");

        ALGORITHMS.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WithECDSA");
        ALGORITHMS.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WithECDSA");
        ALGORITHMS.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WithECDSA");
        ALGORITHMS.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WithECDSA");
        ALGORITHMS.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WithECDSA");

        ALGORITHMS.put(PKCSObjectIdentifiers.md2WithRSAEncryption, "MD2WithRSA");
        ALGORITHMS.put(PKCSObjectIdentifiers.md5WithRSAEncryption, "MD5WithRSA");

        ALGORITHMS.put(PKCSObjectIdentifiers.sha1WithRSAEncryption, "SHA1WithRSA");
        ALGORITHMS.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WithRSA");
        ALGORITHMS.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WithRSA");
        ALGORITHMS.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WithRSA");
        ALGORITHMS.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WithRSA");

        ALGORITHMS.put(GMObjectIdentifiers.sm2sign_with_sha1, "SHA1WithSM2");
        ALGORITHMS.put(GMObjectIdentifiers.sm2sign_with_sha256, "SHA256WithSM2");
        ALGORITHMS.put(GMObjectIdentifiers.sm2sign_with_sm3, "SM3WithSM2");
        
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes128_ECB, "AES-128/ECB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes192_ECB, "AES-192/ECB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes256_ECB, "AES-256/ECB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes128_CBC, "AES-128/CBC");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes192_CBC, "AES-192/CBC");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes256_CBC, "AES-256/CBC");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes128_CFB, "AES-128/CFB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes192_CFB, "AES-192/CFB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes256_CFB, "AES-256/CFB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes128_OFB, "AES-128/OFB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes192_OFB, "AES-192/OFB");
        ALGORITHMS.put(NISTObjectIdentifiers.id_aes256_OFB, "AES-256/OFB");
        
        ALGORITHMS.put(PKCSObjectIdentifiers.RC2_CBC, "RC2/CBC");
        ALGORITHMS.put(PKCSObjectIdentifiers.rc4, "RC4");
        
        ALGORITHMS.put(OIWObjectIdentifiers.desECB, "DES/ECB/PKCS5");
        ALGORITHMS.put(OIWObjectIdentifiers.desCBC, "DES/CBC/PKCS5");
        
        ALGORITHMS.put(OIWObjectIdentifiers.desEDE, "DESede/ECB");
//        ALGORITHMS.put(OIWObjectIdentifiers.desEDE, "DESede/ECB/PKCS5");
//        ALGORITHMS.put(OIWObjectIdentifiers.desEDE, "DESede/ECB/PKCS7");
        ALGORITHMS.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede/CBC");
        ALGORITHMS.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede/CBC/PKCS5");
        ALGORITHMS.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede/CBC/PKCS7");
        
        ALGORITHMS.put(GMObjectIdentifiers.sm2encrypt, "SM2");
        
        ALGORITHMS.put(GMObjectIdentifiers.sms4_ecb, "SM4/ECB");
        ALGORITHMS.put(GMObjectIdentifiers.sms4_cbc, "SM4/CBC");
        
        ALGORITHMS.put(IANAObjectIdentifiers.hmacMD5, "HmacMD5");
        ALGORITHMS.put(IANAObjectIdentifiers.hmacSHA1, "HmacSHA1");
        ALGORITHMS.put(PKCSObjectIdentifiers.id_hmacWithSHA224, "HmacSHA224");
        ALGORITHMS.put(PKCSObjectIdentifiers.id_hmacWithSHA256, "HmacSHA256");
        ALGORITHMS.put(PKCSObjectIdentifiers.id_hmacWithSHA384, "HmacSHA384");
        ALGORITHMS.put(PKCSObjectIdentifiers.id_hmacWithSHA512, "HmacSHA512");
        ALGORITHMS.put(GMObjectIdentifiers.hmac_sm3, "HmacSM3");

        DIGESTS.put(PKCSObjectIdentifiers.md2, "MD2");
        DIGESTS.put(PKCSObjectIdentifiers.md4, "MD4");
        DIGESTS.put(PKCSObjectIdentifiers.md5, "MD5");
        DIGESTS.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
        DIGESTS.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
        DIGESTS.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
        DIGESTS.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
        DIGESTS.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
        DIGESTS.put(NISTObjectIdentifiers.id_sha3_224, "SHA3-224");
        DIGESTS.put(NISTObjectIdentifiers.id_sha3_256, "SHA3-256");
        DIGESTS.put(NISTObjectIdentifiers.id_sha3_384, "SHA3-384");
        DIGESTS.put(NISTObjectIdentifiers.id_sha3_512, "SHA3-512");
        DIGESTS.put(GMObjectIdentifiers.sm3, "SM3");
    }

    public boolean hasAlgorithmName(ASN1ObjectIdentifier objectIdentifier) {
        return ALGORITHMS.containsKey(objectIdentifier);
    }

    public String getAlgorithmName(ASN1ObjectIdentifier objectIdentifier) {
        String name = (String) ALGORITHMS.get(objectIdentifier);
        if (name != null) {
            return name;
        }
        return objectIdentifier.getId();
    }

    public String getAlgorithmName(AlgorithmIdentifier algorithmIdentifier) {
        ASN1Encodable params = algorithmIdentifier.getParameters();
        if (params != null && !DERNull.INSTANCE.equals(params)) {
            if (algorithmIdentifier.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) {
                RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
                AlgorithmIdentifier mgfAlg = rsaParams.getMaskGenAlgorithm();
                if (mgfAlg.getAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1)) {
                    AlgorithmIdentifier digAlg = rsaParams.getHashAlgorithm();
                    ASN1ObjectIdentifier mgfHashOid = AlgorithmIdentifier.getInstance(mgfAlg.getParameters()).getAlgorithm();
                    if (mgfHashOid.equals(digAlg.getAlgorithm())) {
                        return getDigestName(digAlg.getAlgorithm()) + "WITHRSAANDMGF1";
                    } else {
                        return getDigestName(digAlg.getAlgorithm()) + "WITHRSAANDMGF1USING" + getDigestName(mgfHashOid);
                    }
                }
                return getDigestName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAAND" + mgfAlg.getAlgorithm().getId();
            }
        }

        if (ALGORITHMS.containsKey(algorithmIdentifier.getAlgorithm())) {
            return (String) ALGORITHMS.get(algorithmIdentifier.getAlgorithm());
        }

        return algorithmIdentifier.getAlgorithm().getId();
    }

    private static String getDigestName(ASN1ObjectIdentifier oid) {
        String name = (String) DIGESTS.get(oid);
        if (name != null) {
            return name;
        }
        return oid.getId();
    }
}
